#include <iostream>
#include <stdlib.h> //Needed for "exit" function
#include "OpenGL.h"
#include "Util/GameController.h"
#include "Util/ObjectController.h"
#include "Util/Logger.h"
#include "Util/Str.h"
#include "MyObjects.h"
#include <assert.h>

using namespace std;

//PROTOTYPES{
void handleKeypress(unsigned char key, int x, int y);
void handleKeyup(unsigned char key, int x, int y);
void handleSpecialKeys(int key, int x, int y);
void handleSpecialKeysUp(int key, int x, int y);
void handleMouse(int key, int state, int x, int y);
void initRendering();
void handleResize(int w, int h);
void errListener(const char *whosFault);
void drawScene();
void handleMouseMotion(int x, int y);
void fpsTimer(int blank);
//}PROTOTYPES

void fpsTimer(int blank){
	glutTimerFunc(1000/gameController.getFPS(), fpsTimer, 0);
	glutPostRedisplay();
}
void handleKeypress(unsigned char key, int x, int y){
    objectController.key(key);
	if (key==27){exit(0);}//Escape key
}
void handleKeyup(unsigned char key, int x, int y){
	objectController.keyUp(key);
}
void handleSpecialKeys(int key, int x, int y){
    objectController.specialKey(key);
}
void handleSpecialKeysUp(int key, int x, int y){
	objectController.specialKeyUp(key);
}
void handleMouse(int key, int state, int x, int y){
    unsigned char mb;
    switch (key)
    {
        case GLUT_LEFT_BUTTON:
            mb=1;
            break;
        case GLUT_RIGHT_BUTTON:
            mb=2;
            break;
        case GLUT_MIDDLE_BUTTON:
            mb=3;
            break;
        default:
            errLog.print(Str()<<"Unknown mouse event: "<<key);
            return;
    }
    if (state==GLUT_DOWN)
    {
        objectController.mouseDown(mb,x,y);
        objectController.mouseConst(x, y);
    }
    else if (state==GLUT_UP){objectController.mouseUp(mb,x,y);}
}
void handleMouseMotion(int x, int y){
    objectController.mouseConst(x, y);
}
void initRendering(){
    glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
	//Makes 3D drawing work when something is in front of something else
	glEnable(GL_DEPTH_TEST);
}
void handleResize(int w, int h){
	//Tell OpenGL how to convert from coordinates to pixel values
	glViewport(0, 0, w, h);
	
	glMatrixMode(GL_PROJECTION); //Switch to setting the camera perspective
	
	//Set the camera perspective
	glLoadIdentity(); //Reset the camera
    //gluOrtho2D(0,w,0,h);
	gluPerspective(45.0,                  //The camera angle
				   (double)w / (double)h, //The width-to-height ratio
				   1.0,                   //The near z clipping coordinate
				   200.0);                //The far z clipping coordinate
    gluLookAt(0, 0, 100, 0, 0, 0, 0, 1, 0);
}
void drawScene(){
#ifdef DIE_ON_NO_CAMERA
	if (objectController.getNumberOfCameras()==0)
	{
		errLog.print("NO CAMERAS!");
		assert(!"NO CARMERAS!");
	}
#endif
	gameController.__sysFPS();
    objectController.step();
    gameLib.errListener("Object Step");
	
    glMatrixMode(GL_PROJECTION); //Switch to setting the camera perspective
	glLoadIdentity(); //Reset the camera
    objectController.cameraSetup();
    gameLib.errListener("Camera Setup");
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);//Clear information from last draw
	
	glMatrixMode(GL_MODELVIEW); //Switch to the drawing perspective
	glLoadIdentity(); //Reset the drawing perspective
    objectController.draw();
	gameLib.errListener("3D Drawing");
	
	if (gameController.isLightingEnabled())
	{
		glDisable(GL_LIGHTING);
	}
	
	glMatrixMode(GL_PROJECTION);
	gluOrtho2D(-1, 1, 1, -1);
	glLoadIdentity();
	objectController.drawOrtho();
	gameLib.errListener("2D Drawing");
	
	if (gameController.isLightingEnabled())
	{
		glEnable(GL_LIGHTING);
	}
	
	glutSwapBuffers(); //Send the scene to the screen
}
int main(int argc, char** argv){
    mainLog.print("THIS IS 3D LAND");
	//Initialize GLUT
	glutInit(&argc, argv);
	glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
	glutInitWindowSize(gameController.getWidth(), gameController.getHeight()); //Set the window size
	
	//Create the window
	glutCreateWindow(!gameController.getTitle());
	initRendering(); //Initialize rendering
	
	//Set handler functions for drawing, keypresses, and window resizes
	glutDisplayFunc(drawScene);
	glutKeyboardFunc(handleKeypress);
	glutKeyboardUpFunc(handleKeyup);
    glutSpecialFunc(handleSpecialKeys);
	glutSpecialUpFunc(handleSpecialKeysUp);
    glutMouseFunc(handleMouse);
    glutMotionFunc(handleMouseMotion);
    glutPassiveMotionFunc(handleMouseMotion);
	glutReshapeFunc(handleResize);
    
    gameController.init();
	gameLib.errListener("gameController.init()");
	fpsTimer(0);
    
    createObjects();
	gameLib.errListener("Creating the objects");
	
	glutMainLoop(); //Start the main loop.  glutMainLoop doesn't return.
	return 0; //This line is never reached
}
